package com.ruoyi.heima.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.MqConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.heima.domain.dto.QueryNewsPageDto;
import com.ruoyi.heima.domain.po.News;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.heima.enums.NewsStatus;
import com.ruoyi.heima.mapper.NewsMapper;
import com.ruoyi.heima.service.INewsService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

/**
 * 新闻管理Service业务层处理
 *
 * @author yangjianlin
 * @date 2025-02-10
 */
@Service
public class NewsServiceImpl extends ServiceImpl<NewsMapper, News> implements INewsService {
    @Autowired
    private NewsMapper newsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 查询新闻管理列表
     *
     * @param dto 新闻管理
     * @return
     */
    @Override
    public List<News> selectNewsList(QueryNewsPageDto dto) {
        List<News> newsList = new ArrayList<>();
        // 如果searchValue不为空 则对searchValue做分割处理
        List<Long> typeIds = null;
        if (StringUtils.isNotEmpty(dto.getSearchValue())) {
            String searchValue = dto.getSearchValue();
            typeIds = Arrays.stream(searchValue.split(","))
                    .filter(StringUtils::isNotBlank)
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
        }
        // 查询符合条件的数据库新闻列表
        // sql = "select * from tb_news where status != '已删除' and title = #{title} and source = #{source} and type_id in (#{typeIds}) and status = #{status}"
        newsList = lambdaQuery().ne(dto.getStatus()!=NewsStatus.DELETED,News::getStatus, NewsStatus.DELETED)
                .like(StringUtils.isNotEmpty(dto.getTitle()), News::getTitle, dto.getTitle())
                .like(StringUtils.isNotEmpty(dto.getSource()), News::getSource, dto.getSource())
                .in(CollectionUtils.isNotEmpty(typeIds), News::getTypeId, typeIds)
                .eq(ObjectUtils.isNotEmpty(dto.getStatus()), News::getStatus, dto.getStatus())
                .orderByDesc(News::getNewsId)
                .list();

        return newsList;
    }

    /**
     * 根据id查询新闻
     *
     * @param newsId 新闻管理主键
     * @return 新闻管理
     */
    @Override
    public News selectNewsByNewsId(Long newsId) {
        News news = lambdaQuery().eq(News::getNewsId, newsId).one();
        return news;
    }

    /**
     * 新增新闻
     *
     * @param news 新闻管理
     * @return 结果
     */
    @Override
    public int insertNews(News news) {
        news.setCreateTime(DateUtils.getNowDate());
        int count = newsMapper.insert(news);
        return count;
    }


    /**
     * 修改新闻
     *
     * @param news 新闻管理
     * @return 结果
     */
    @Override
    public Boolean updateNews(News news) {
        news.setUpdateTime(DateUtils.getNowDate());
        return updateById(news);
    }

    /**
     * 删除新闻
     * @param newsId 新闻管理主键
     * @return 结果
     */
    @Override
    public Boolean deleteNewsByNewsId(Long newsId) {
        // 根据新闻id 逻辑删除新闻(设置新闻状态为DELETE)---更新状态
        boolean tag = lambdaUpdate().eq(News::getNewsId, newsId)
                .set(News::getStatus, NewsStatus.DELETED)
                .update();
        return tag;
    }

    /**
     * 批量删除新闻
     *
     * @param newsIds 需要删除的新闻管理主键
     * @return 结果
     */
    @Override
    public Boolean deleteNewsByNewsIds(Long[] newsIds) {
        boolean tag = lambdaUpdate().in(News::getNewsId, newsIds)
                .set(News::getStatus, NewsStatus.DELETED)
                .update();
        return tag;
    }

    /**
     * 批量发送新闻
     *
     * @param newsIds
     * @return
     */
    @Override
    public void pushNews(List<Long> newsIds) {
        // 推送新闻
        for (Long newsId : newsIds) {
            // 查询新闻
            News news = selectNewsByNewsId(newsId);
            if (news != null) {
                // 判断新闻是否延迟发布
                if (news.getDelayTime() == 0) {
                    news.setStatus(NewsStatus.PUBLISH);
                } else {
                    news.setStatus(NewsStatus.DELAY_PUBLISH);
                }
                // 更新新闻
                updateById(news);
                // 发送消息
                rabbitTemplate.convertAndSend(MqConstants.DELAY_NEWS_EXCHANGE, MqConstants.DELAY_PUBLISH_ROUTING_KEY, news,
                        new MessagePostProcessor() {
                            @Override
                            public Message postProcessMessage(Message message) throws AmqpException {
                                message.getMessageProperties().setDelay(news.getDelayTime() * 60 * 1000);
                                return message;
                            }
                        });
            }
        }
    }

    /**
     * 根据通知公告id查询新闻
     * @param noticeId
     * @return
     */
    @Override
    public News selectNewsByNoticeId(Long noticeId) {
        News news = lambdaQuery().eq(News::getNoticeId, noticeId).one();
        return news;
    }

    /**
     * 查询全部新闻
     * @return
     */
    @Override
    public List<News> selectAllNewList() {
        return lambdaQuery().list();
    }

    /**
     * 删除一周前更新并状态为删除的新闻
     */
    @Override
    public void deletedOneWeekAgoNews() {
        // 获取一周前的日期
        LocalDate oneWeekAgoDate = LocalDate.now().minus(1, ChronoUnit.WEEKS);
        // 获取一周前的新闻
        List<News> newsList = lambdaQuery().eq(News::getStatus, NewsStatus.DELETED)
                .le(News::getUpdateTime, oneWeekAgoDate)
                .list();
        // 获取列表中所有的newsId
        List<Long> newsIds = newsList.stream().map(News::getNewsId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(newsIds)) {
            // 批量删除新闻
            removeByIds(newsIds);
        }
    }

    @Override
    public List<News> selectNewsByIdsCache(List<Long> ids) {
        List<News> newsList = new ArrayList<>();
        // 判断ids不为空
        if (CollectionUtils.isNotEmpty(ids)){
            for (Long id : ids) {
                // 查看新闻是否在缓存中
                News news = (News) redisTemplate.opsForValue().get("news:" + id);
                // 如果redis数据不为空，则数据有缓存
                if (news != null) {
                    newsList.add(news);
                } else {
                    // 如果reids数据为空，则去数据库查询数据，然后缓存到redis
                    News DBNews = getById(id);
                    if (DBNews != null){
                        // 缓存到redis
                        redisTemplate.opsForValue().set("news:" + id, DBNews);
                        // 添加到返回结果集合
                        newsList.add(DBNews);
                    }else {
                        // 解决缓存穿透问题，设置空值
                        News nullNews = new News();
                        nullNews.setTitle("空新闻");
                        redisTemplate.opsForValue().set("news:" + id, null);
                    }
                }
            }
        }
        return newsList;
    }

    /**
     * 同步通知通告删除新闻(真删数据库的数据)
     *
     * @param noticeIds 通知公告id
     * @return 新闻管理
     */
    @Override
    public Boolean deleteNewsFromNotice(Long[] noticeIds) {
        boolean tag = lambdaUpdate().in(News::getNoticeId, noticeIds)
                .set(News::getStatus, NewsStatus.DELETED)
                .remove();
        return tag;
    }
}
